@namespace Bit.BlazorUI
@typeparam TGridItem

@{
    InternalGridContext.Grid.AddColumn(this, IsDefaultSort);
}

@code
{
    [CascadingParameter] internal InternalGridContext<TGridItem> InternalGridContext { get; set; } = default!;

    /// <summary>
    /// Title text for the column. This is rendered automatically if <see cref="HeaderTemplate" /> is not used.
    /// </summary>
    [Parameter] public string? Title { get; set; }

    /// <summary>
    /// An optional CSS class name. If specified, this is included in the class attribute of table header and body cells
    /// for this column.
    /// </summary>
    [Parameter] public string? Class { get; set; }

    /// <summary>
    /// If specified, controls the justification of table header and body cells for this column.
    /// </summary>
    [Parameter] public BitDataGridAlign Align { get; set; }

    /// <summary>
    /// An optional template for this column's header cell. If not specified, the default header template
    /// includes the <see cref="Title" /> along with any applicable sort indicators and options buttons.
    /// </summary>
    [Parameter] public RenderFragment<BitDataGridColumnBase<TGridItem>>? HeaderTemplate { get; set; }

    /// <summary>
    /// If specified, indicates that this column has this associated options UI. A button to display this
    /// UI will be included in the header cell by default.
    ///
    /// If <see cref="HeaderTemplate" /> is used, it is left up to that template to render any relevant
    /// "show options" UI and invoke the grid's <see cref="BitDataGrid{TGridItem}.ShowColumnOptions(BitDataGridColumnBase{TGridItem})" />).
    /// </summary>
    [Parameter] public RenderFragment? ColumnOptions { get; set; }

    /// <summary>
    /// Indicates whether the data should be sortable by this column.
    ///
    /// The default value may vary according to the column type (for example, a <see cref="BitDataGridTemplateColumn{TGridItem}" />
    /// is sortable by default if any <see cref="BitDataGridTemplateColumn{TGridItem}.SortBy" /> parameter is specified).
    /// </summary>
    [Parameter] public bool? Sortable { get; set; }

    /// <summary>
    /// If specified and not null, indicates that this column represents the initial sort order
    /// for the grid. The supplied value controls the default sort direction.
    /// </summary>
    [Parameter] public BitDataGridSortDirection? IsDefaultSort { get; set; }

    /// <summary>
    /// If specified, virtualized grids will use this template to render cells whose data has not yet been loaded.
    /// </summary>
    [Parameter] public RenderFragment<PlaceholderContext>? PlaceholderTemplate { get; set; }

    /// <summary>
    /// Gets a reference to the enclosing <see cref="BitDataGrid{TGridItem}" />.
    /// </summary>
    public BitDataGrid<TGridItem> Grid => InternalGridContext.Grid;

    /// <summary>
    /// Overridden by derived components to provide rendering logic for the column's cells.
    /// </summary>
    /// <param name="builder">The current <see cref="RenderTreeBuilder" />.</param>
    /// <param name="item">The data for the row being rendered.</param>
    protected internal abstract void CellContent(RenderTreeBuilder builder, TGridItem item);

    /// <summary>
    /// Gets or sets a <see cref="RenderFragment" /> that will be rendered for this column's header cell.
    /// This allows derived components to change the header output. However, derived components are then
    /// responsible for using <see cref="HeaderTemplate" /> within that new output if they want to continue
    /// respecting that option.
    /// </summary>
    protected internal RenderFragment HeaderContent { get; protected set; }

    /// <summary>
    /// Get a value indicating whether this column should act as sortable if no value was set for the
    /// <see cref="BitDataGridColumnBase{TGridItem}.Sortable" /> parameter. The default behavior is not to be
    /// sortable unless <see cref="BitDataGridColumnBase{TGridItem}.Sortable" /> is true.
    ///
    /// Derived components may override this to implement alternative default sortability rules.
    /// </summary>
    /// <returns>True if the column should be sortable by default, otherwise false.</returns>
    protected virtual bool IsSortableByDefault() => false;

    /// <summary>
    /// Constructs an instance of <see cref="BitDataGridColumnBase{TGridItem}" />.
    /// </summary>
    public BitDataGridColumnBase()
    {
        HeaderContent = RenderDefaultHeaderContent;
    }

    private void RenderDefaultHeaderContent(RenderTreeBuilder __builder)
    {
        @if (HeaderTemplate is not null)
        {
            @HeaderTemplate(this)
        }
        else
        {
            @if (ColumnOptions is not null && Align != BitDataGridAlign.Right)
            {
                <button type="button" class="bit-dtg-cob" @onclick="@(() => Grid.ShowColumnOptions(this))"></button>
            }

            if (Sortable.HasValue ? Sortable.Value : IsSortableByDefault())
            {
                <button type="button" class="bit-dtg-ctl" @onclick="@(() => Grid.SortByColumnAsync(this))">
                    <div class="bit-dtg-ctt">@Title</div>
                    <div class="bit-dtg-srt" aria-hidden="true"></div>
                </button>
            }
            else
            {
                <div class="bit-dtg-ctl">
                    <div class="bit-dtg-ctt">@Title</div>
                </div>
            }

            @if (ColumnOptions is not null && Align == BitDataGridAlign.Right)
            {
                <button type="button" class="bit-dtg-cob" @onclick="@(() => Grid.ShowColumnOptions(this))"></button>
            }
        }
    }

    internal void RenderPlaceholderContent(RenderTreeBuilder __builder, PlaceholderContext placeholderContext)
    {
        // Blank if no placeholder template was supplied, as it's enough to style with CSS by default
        if (PlaceholderTemplate is not null)
        {
            @PlaceholderTemplate(placeholderContext)
        }
    }
}
